<script lang="tsx">
import {defineComponent, ref, shallowRef, watch} from "vue";
import {TableProps, tableProps} from "/@/components/Base/BaseEditTable/ts";
import useTableHooks from "/@/components/Base/BaseEditTable/hooks/TableDataHook";
import {ElMessage, ElTable, ElTableColumn} from "element-plus";
import {Column} from "/@/components/Base/BaseEditTable/ts";
import {TableRow} from "/@/components/Base/BaseEditTable/ts";
import {componentMap} from "/@/components/Base/BaseEditTable/ts/ComponentMap";
import {OnClickOutside} from '@vueuse/components'
import {Warning} from "@element-plus/icons-vue";
import _ from 'lodash-es'
export default defineComponent({
    name: "BaseEditTable",
    props: tableProps,
    setup(props: TableProps, {expose, emit, slots}) {
        const tableVariable = useTableHooks()
        //编辑锁，同时只能一个字段进行编辑
        const editState = ref(false)
        //单元格组件Ref
        const cellRef = ref()
        //排除的class
        const classNames = ["el-select-dropdown__item hover", "el-select-dropdown__item", "el-input edit-cell","el-input-number edit-cell", "el-select w-full edit-cell","el-select-dropdown__wrap el-scrollbar__wrap el-scrollbar__wrap--hidden-default"]
        // 错误提示
        const errorMessage = shallowRef('')
        const editObject = ref({
            index: -1,
            prop: '',
            row: {
                //设置正在编辑的字段
                $editField: '',
                //设置正在编辑的行 1、正在编辑 2、编辑结束
                $isEdit: 2,
                //标记当前行的编辑状态 0、原始状态 1、新增状态 2、修改状态
                $editState: 0,
                //处于报警状态的字段列表
                $errorList: []
            },
        })


        function clickShow(scope, item, selectObj, el) {
            if (editState.value) {
                return
            }
            scope.row.$isEdit = 1
            scope.row.$editField = item.prop
            editState.value = true
            selectObj.getFocus(cellRef)
            if (el) {
                //特殊组件比如switch调用
                cancelShow(el, scope.row)
            }
        }

        /**
         * 解除编辑状态
         */
        const relievesEdit = () => {
            //解除当前单元格的编辑状态
            editObject.value.row.$editField = ''
            editObject.value.row.$isEdit = 2
            editState.value = false
            //去掉验证未通过的感叹号
            if (editObject.value.row.$errorList && editObject.value.row.$errorList.length > 0) {
                editObject.value.row.$errorList = editObject.value.row.$errorList.filter(r => r != editObject.value.prop)
            }
        }

        /**
         * 取消当前单元格的显示状态，并标记当前行为修改状态
         * @param el
         */
        const cancelShow = (el, row) => {
            //判断是否为标签内部元素，比如select选择框弹出的气泡
            const paths = el.composedPath()
            const currentClassNames = paths.map((res) => res.className);
            for (let i = 0; i < currentClassNames.length; i++) {
                if (currentClassNames[i] && classNames.includes(currentClassNames[i])) {
                    return;
                }
            }
            //将当前行设置为修改状态
            editObject.value.row.$editState = 2
            if (row) {
                //只有像switch这样的特殊组件会进入
                row.$editField = ''
                row.$isEdit = 2
                editState.value = false
                return;
            }
            if (editObject.value.row && editObject.value.row.$editField) {
                //校验当前值
                if (tableVariable.validator.value) {
                    tableVariable.validator.value.validate({...editObject.value.row}, (errors) => {
                        let error: any = undefined;
                        if (errors) {
                            //只获取当前字段的第一个错误信息
                            error = errors.find(r => r.field == editObject.value.row.$editField);
                        }
                        if (!error) {
                            //校验通过
                            //解除编辑状态
                            relievesEdit()
                        } else {
                            //校验未通过
                            errorMessage.value = error.message
                        }
                    });
                }else{
                    //解除编辑状态
                    relievesEdit()
                }
            }
        }
        /**
         * 引用组件参数
         */
        const attr = {
            onTrigger: (el: any) => cancelShow(el, null)
        }

        const getComponent = (scope, item) => {
            let o = componentMap.get(item.component);
            let selectObj = _.cloneDeep(o)
            selectObj.setProperties(scope.row[item.prop], item.componentAttr)
           
            if (!selectObj.whetherFormat()) {
                //直接显示组件的表格栏，例如switch
                const dynamicComponent = selectObj.getComponent()
                return <OnClickOutside {...attr} >
                    <dynamicComponent onClick={(event) => clickShow(scope, item.label, selectObj, event)}
                                      class="edit-cell" {...item.componentAttr}
                                      v-model={scope.row[item.prop]}></dynamicComponent>
                </OnClickOutside>
            }
            if ((scope.row.$isEdit == 1 && scope.row.$editField == item.prop)) {
                //处于编辑状态
                editObject.value = {
                    prop: item.prop,
                    row: scope.row,
                    index: scope.$index
                }

                const dynamicComponent = selectObj.getComponent()
                return <OnClickOutside {...attr} >
                    <dynamicComponent ref={cellRef} class="edit-cell" {...item.componentAttr}
                                      v-model={scope.row[item.prop]}></dynamicComponent>
                </OnClickOutside>

            }
            //字段报警状态
            if (scope.row.$errorList && scope.row.$errorList.includes(item.prop)) {
                return <div class="h-7 w-full flex" onClick={() => clickShow(scope, item, selectObj, null)}>
                    <div class="flex-1">
                        {selectObj.formatLabel()}
                    </div>
                    <div class="w-2.5 flex items-center">
                        <el-icon color="#FF0000"><Warning/></el-icon>
                    </div>
                </div>
            }
            //未编辑状态
            return <div class="h-7 w-full"
                        onClick={() => clickShow(scope, item, selectObj, null)}>{selectObj.formatLabel()}</div>
        }

        expose({
            setData: tableVariable.setData,
            getData: tableVariable.getData,
            setRules: tableVariable.setRules,
            add: tableVariable.add,
            addAll: tableVariable.addAll,
            remove: tableVariable.remove,
            validate: tableVariable.validate
        })
        watch(() => errorMessage.value, (newValue) => {
            if (newValue) {
                ElMessage.warning(newValue)
                let timer = setTimeout(() => {
                    errorMessage.value = ''
                    clearTimeout(timer);
                }, 1000);
            }
        })

        const render = () => {

            return (
                <ElTable {...props.tableAttr} data={tableVariable.tableData.value}>
                    {props.columns?.map((item: Column) => {
                        if (item.type) {
                            let items = {
                                align: item.align,
                                width: item.width,
                                fixed: item.fixed,
                            } as any
                            return <ElTableColumn  {...items} type={item.type} label={item.label}>
                            </ElTableColumn>
                        }
                        let items = {
                            type: item.type,
                            fixed: item.fixed,
                            align: item.align,
                            width: item.width,
                        } as any
                        return <ElTableColumn {...items} prop={item.prop} label={item.label}>
                            {{
                                default: (scope: TableRow) => {
                                    if (item.custom) {
                                        return slots[item.custom]?.(scope, item)
                                    }
                                    return getComponent(scope, item)
                                }
                            }}
                        </ElTableColumn>
                    })}
                </ElTable>
            )
        }
        return render
    }
})

</script>